export default class CustomTransform {
  constructor({ sandbox, size = 1 }) {
    this.sandbox = sandbox
    this.scene = sandbox.scene
    this._size = size
    // 整体
    this._show = false
    // 三个控件的单个轴显隐
    this._showX = false
    this._showY = false
    this._showZ = false
    // 平移的轴显隐
    this._showTX = false
    this._showTX = false
    this._showTY = false
    // 旋转的轴显隐
    this._showRY = false
    this._showRZ = false
    this._showRZ = false
    // 缩放的轴显隐
    this._showSY = false
    this._showSZ = false
    this._showSZ = false
    this.overlay = new GC.Object3D()
    this.initOverlay()
  }

  initOverlay() {
    const { camera, renderer } = this.sandbox
    const controls = [
      { translate: { size: 1 * this._size, space: 'local' } },
      { rotate: { size: 0.8 * this._size, space: 'local' } },
      { scale: { size: 1.3 * this._size, space: 'world' } }
    ]

    controls.forEach(controlConfig => {
      const [key, value] = Object.entries(controlConfig)[0]

      const control = new GC.CustomTransformControls(camera, renderer.domElement)
      control.visible = this._show
      control.controlType = key
      control.setMode(key)
      control.setSpace(value.space)
      control.size = value.size

      control.traverse(child => {
        child.userData.ignoreRaycast = true
      })

      this.overlay.add(control)
      this.setupControlEvents(control)
    })
    this.scene.add(this.overlay)
    this.setupGlobalEventListeners()
  }

  // 局部事件
  setupControlEvents(control) {
    control.addEventListener('dragging-changed', event => {
      this.sandbox.controls.enabled = !event.value
    })

    control.addEventListener('mouseDown', () => this.toggleVisibility(false))
    control.addEventListener('mouseUp', () => this.toggleVisibility(true))
  }

  toggleVisibility(visible) {
    if (!this.attachObj) return
    this.overlay.children.forEach(item => {
      if (!item.dragging) {
        item.enabled = visible
        item.visible = visible
      }
    })
  }

  // 全局事件
  setupGlobalEventListeners() {
    this.handleKeyDown = this.handleKeyDown.bind(this)
    this.handleKeyUp = this.handleKeyUp.bind(this)

    window.addEventListener('keydown', this.handleKeyDown)
    window.addEventListener('keyup', this.handleKeyUp)
  }

  handleKeyDown(event) {
    if (!this.attachObj) return
    const arr = this.overlay.children

    switch (event.key) {
      case 'q': // 切换世界/本地空间
        arr.forEach(item => {
          item.setSpace(item.space === 'local' ? 'world' : 'local')
        })
        break

      case 'Shift': // 切换网格
        arr.forEach(item => {
          item.setTranslationSnap(1)
          item.setRotationSnap(GC.MathUtils.degToRad(15))
          item.setScaleSnap(0.25)
        })
        break

      case ' ':
        arr.forEach(item => {
          item.enabled = !item.enabled
        })
        break

      case 'Escape':
        arr.forEach(item => {
          item.reset()
        })
        break
    }
  }

  handleKeyUp(event) {
    if (!this.attachObj) return
    const arr = this.overlay.children

    switch (event.key) {
      case 'Shift':
        arr.forEach(item => {
          item.setTranslationSnap(null)
          item.setRotationSnap(null)
          item.setScaleSnap(null)
        })
        break
    }
  }

  attach(mesh) {
    this.attachObj = mesh
    this.overlay.children.forEach(item => {
      item.attach(mesh)
    })
  }

  detach() {
    this.attachObj = null
    this.overlay.children.forEach(item => {
      item.detach()
    })
  }

  destroy() {
    // 移除全局事件监听器
    window.removeEventListener('keydown', this.handleKeyDown)
    window.removeEventListener('keyup', this.handleKeyUp)

    this.overlay.dispose()
  }

  space() {
    this.overlay.children.forEach(item => {
      item.setSpace(item.space === 'local' ? 'world' : 'local')
    })
  }

  get size() {
    return this._size
  }

  set size(val) {
    this._size = val
    this.overlay.children[0].size = this._size
    this.overlay.children[1].size = 0.8 * this._size
    this.overlay.children[2].size = 1.3 * this._size
  }

  get show() {
    return this._show
  }

  set show(val) {
    this._show = val
    this.overlay.children.forEach(item => {
      item.visible = val
    })
  }

  get showX() {
    return this._showX
  }

  set showX(val) {
    this._showX = val
    this.overlay.children.forEach(item => {
      item.showX = val
    })
  }

  get showTX() {
    return this._showTX
  }

  set showTX(val) {
    this._showTX = val
    this.overlay.children[0].showX = val
  }

  get showRX() {
    return this._showRX
  }

  set showRX(val) {
    this._showRX = val
    this.overlay.children[1].showX = val
  }

  get showSX() {
    return this._showTX
  }

  set showSX(val) {
    this._showSX = val
    this.overlay.children[2].showX = val
  }

  get showY() {
    return this._showY
  }

  set showY(val) {
    this._showY = val
    this.overlay.children.forEach(item => {
      item.showY = this._showY
    })
  }

  get showTY() {
    return this._showTY
  }

  set showTY(val) {
    this._showTY = val
    this.overlay.children[0].showY = val
  }

  get showRY() {
    return this._showRY
  }

  set showRY(val) {
    this._showRY = val
    this.overlay.children[1].showY = val
  }

  get showSY() {
    return this._showSY
  }

  set showSY(val) {
    this._showSY = val
    this.overlay.children[2].showY = val
  }

  get showZ() {
    return this._showZ
  }

  set showZ(val) {
    this._showZ = val
    this.overlay.children.forEach(item => {
      item.showZ = this._showZ
    })
  }

  get showTZ() {
    return this._showTZ
  }

  set showTZ(val) {
    this._showTZ = val
    this.overlay.children[0].showZ = val
  }

  get showRZ() {
    return this._showRZ
  }

  set showRZ(val) {
    this._showRZ = val
    this.overlay.children[1].showZ = val
  }

  get showSZ() {
    return this._showSZ
  }

  set showSZ(val) {
    this._showSZ = val
    this.overlay.children[2].showZ = val
  }
}
